import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

public class Packet
{
	public int peerID;
	
	public Packet(int peerID)
	{
		this.peerID = peerID;
	}
	
	// sets up the handshake packet data
	public byte[] createHandshakePacket()
	{
		// header needs to be 18 bytes
		String header = "CNT5106C2011FALL  ";
		
		byte[] headerBytes = header.getBytes();
		//System.out.println(headerBytes.length);
		
		// zero bits need to be 10 bytes
		byte[] zeroBitsBytes = new byte[10];
		
		zeroBitsBytes = "0000000000".getBytes();
		
		//for(int i = 0; i < 10; i++)
			//zeroBitsBytes[i] = 0;
		//System.out.println(zeroBitsBytes.length);
		
		// peerID needs to be 4 bytes
		byte[] peerIDBytes = Integer.toString(peerID).getBytes();
		//byte[] peerIDBytes = ByteBuffer.allocate(4).putInt(peerID).array();
		//System.out.println(peerIDBytes.length);
		
		byte[] handshakePacketBytes = new byte[32];
		
		// first 18 bytes of handshake packet is the header
		for(int i = 0; i < 18; i++)
		{
			handshakePacketBytes[i] = headerBytes[i];
		}
			
		// next 10 bytes are zero bits
		int j = 0;
		for(int i = 18; i < 28; i++)
		{
			handshakePacketBytes[i] = zeroBitsBytes[j];
			j++;
		}
			
		// last 4 bytes is the peerID
		j = 0;
		for(int i = 28; i < 32; i++)
		{
			handshakePacketBytes[i] = peerIDBytes[j];
			j++;
		}
		
		return handshakePacketBytes;
	}
	
	/* message types:
	 * choke			0
	 * unchoke			1
	 * interested		2
	 * not interested	3
	 * have				4
	 * bitfield			5
	 * request 			6
	 * piece			7
	 *
	 * message structure:
	 * 4 byte message length, 1 byte message type, message payload
	 *
	 * 'choke', 'unchoke', 'interested', and 'not interested' have no payload
	 * 'have' has a 4 byte piece index payload
	 * 'bitfield' has a bitfield payload
	 * 'request' has a 4 byte piece index payload
	 * 'piece' has a 4 byte piece index and the content of the piece as a payload
	 */
	
	// creates a 'choke' message packet
	public byte[] createChokePacket()
	{
		byte[] chokePacketBytes = new byte[5];

		String choke = "00010";
		chokePacketBytes = choke.getBytes();
		
		// length = 1 byte
		//chokePacketBytes[0] = 0;
		//chokePacketBytes[1] = 0;
		//chokePacketBytes[2] = 0;
		//chokePacketBytes[3] = 1;
		
		// type = 0
		//chokePacketBytes[4] = 0; 
	
		//for(int i = 0; i < 5; i++)
			//System.out.print(Integer.toBinaryString(chokePacketBytes[i]));
		//System.out.println();
		
		return chokePacketBytes;
	}
	
	// creates an 'unchoke' message packet
	public byte[] createUnchokePacket()
	{
		byte[] unchokePacketBytes = new byte[5];

		String unchoke = "00011";
		unchokePacketBytes = unchoke.getBytes();
		
		// length = 1 byte
		//unchokePacketBytes[0] = 0;
		//unchokePacketBytes[1] = 0;
		//unchokePacketBytes[2] = 0;
		//unchokePacketBytes[3] = 1;
		
		// type = 1
		//unchokePacketBytes[4] = 1;
		
		return unchokePacketBytes;
	}
	
	// creates an 'interested' message packet
	public byte[] createInterestedPacket()
	{
		byte[] interestedPacketBytes = new byte[5];
		
		String interested = "00012";
		interestedPacketBytes = interested.getBytes();
		
		// length = 1 byte
		//interestedPacketBytes[0] = 0;
		//interestedPacketBytes[1] = 0;
		//interestedPacketBytes[2] = 0;
		//interestedPacketBytes[3] = 1;
		
		// type = 2
		//interestedPacketBytes[4] = 2;
		
		return interestedPacketBytes;
	}
	
	// creates a 'not interested' message packet
	public byte[] createNotInterestedPacket()
	{
		byte[] notInterestedPacketBytes = new byte[5];
		
		String notInterested = "00013";
		notInterestedPacketBytes = notInterested.getBytes();
		
		// length = 1 byte
		//notInterestedPacketBytes[0] = 0;
		//notInterestedPacketBytes[1] = 0;
		//notInterestedPacketBytes[2] = 0;
		//notInterestedPacketBytes[3] = 1;
		
		// type = 3
		//notInterestedPacketBytes[4] = 3;
		
		return notInterestedPacketBytes;
	}
	
	// creates a 'have' message packet
	public byte[] createHavePacket(int index)
	{
		// total bytes = 4 for length + 1 for type + 4 for piece index = 9
		byte[] havePacketBytes = new byte[9];
		
		String indexString = Integer.toString(index);
		
		// make the index 4 bytes
		while(indexString.length() < 4)
		{
			indexString = "0" + indexString; 
		}
		
		String have = "00054" + indexString;
		
		havePacketBytes = have.getBytes();
		
		// length = 5 bytes (does not include 4 byte length field)
		//havePacketBytes[0] = 0;
		//havePacketBytes[1] = 0;
		//havePacketBytes[2] = 0;
		//havePacketBytes[3] = 5;
		
		// type = 4
		//havePacketBytes[4] = 4;
		
		// 4 byte piece index payload
		
		return havePacketBytes;
	}
	
	// creates a 'bitfield' message packet
	public byte[] createBitfieldPacket(String bitfield)
	{
		byte[] bitfieldPacketBytes = new byte[5];
		
		int length = 1 + bitfield.length();
		String len = Integer.toString(length);
		
		while(len.length() < 4)
		{
			len = "0" + len;
		}
		
		String bitfieldPacket = len + "5" + bitfield;
		
		bitfieldPacketBytes = bitfieldPacket.getBytes();
		
		// type = 5
		//bitfieldPacketBytes[4] = 5;
		
		return bitfieldPacketBytes;
	}
	
	// creates a 'request' message packet
	public byte[] createRequestPacket(int index)
	{
		// total bytes = 4 for length + 1 for type + 4 for piece index = 9
		byte[] requestPacketBytes = new byte[9];
		
		String indexString = Integer.toString(index);
		
		// make the index 4 bytes
		while(indexString.length() < 4)
		{
			indexString = "0" + indexString; 
		}
		
		String have = "00056" + indexString;
		
		requestPacketBytes = have.getBytes();
		
		// length = 5 bytes (does not include 4 byte length field)
		//requestPacketBytes[0] = 0;
		//requestPacketBytes[1] = 0;
		//requestPacketBytes[2] = 0;
		//requestPacketBytes[3] = 5;
		
		// type = 6
		//requestPacketBytes[4] = 6;	
		
		return requestPacketBytes;
	}
	
	// creates a 'piece' message packet
	public byte[] createPiecePacket(int index)
	{
		ConfigReader cfg = new ConfigReader();
		cfg.readCommon();
		
		String fileName = "peer_" + peerID + "/" + cfg.fileName + index;
		int pieceSize = cfg.pieceSize;
		String indexStr = Integer.toString(index);
		
		byte[] piece = new byte[pieceSize];
		int actualSize = 0;
		
		// read in the piece into the piece byte array
		try 
		{
			FileInputStream fis = new FileInputStream(fileName);
			actualSize = fis.read(piece);
		}
		catch (FileNotFoundException e)
		{
			e.printStackTrace();
		} 
		catch (IOException e)
		{
			e.printStackTrace();
		}
		
		System.out.println(actualSize);
		
		int length = 1 + indexStr.length() + actualSize;
		String len = Integer.toString(length);
		
		// create the packet header
		while(len.length() < 4)
		{
			len = "0" + len;
		}
		
		System.out.println(len);
		
		String header = len + "7" + indexStr;
		
		System.out.println(header);
		
		byte[] headerBytes = header.getBytes();
		
		byte[] piecePacketBytes = new byte[header.length()+actualSize];
		
		// concatenate the byte arrays
		for(int i = 0; i < header.length(); i++)
		{
			piecePacketBytes[i] = headerBytes[i];
		}
		for(int i = header.length(); i < (header.length()+actualSize); i++)
		{
			piecePacketBytes[i] = piece[i-header.length()];
		}
		
		//byte[] piecePacketBytes = new byte[5];
		
		// type = 7
		//piecePacketBytes[4] = 7;
		
		return piecePacketBytes;
	}
}
